package com.suyunyou.spider.utils;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.suyunyou.spider.plugins.ILinkPlugin;
import com.suyunyou.spider.plugins.IPagePlugin;
import com.system.comm.utils.FrameJsonUtil;

/**
 * 下载页面内容
 * @author 岳静
 * @date 2016年6月24日 下午3:33:02 
 * @version V1.0
 */
public class PluginUtil {

	private static final Logger LOGGER = LoggerFactory.getLogger(PluginUtil.class);

	private static Map<String, List<Class<?>>> classMap = new HashMap<String, List<Class<?>>>();

	private static List<IPagePlugin> pagePlugins = new ArrayList<IPagePlugin>();
	private static List<ILinkPlugin> linkPlugins = new ArrayList<ILinkPlugin>();

	/**
	 * 添加插件
	 * @param plugin
	 */
	public static void addIPagePlugin(IPagePlugin plugin) {
		pagePlugins.add(plugin);
	}

	/**
	 * 添加插件
	 * @param plugin
	 */
	public static void addILinkPlugin(ILinkPlugin plugin) {
		linkPlugins.add(plugin);
	}

	/**
	 * 清空所有插件
	 */
	public static void clearPlugins() {
		pagePlugins.clear();
		linkPlugins.clear();
	}

	/**
	 * 获取所有插件
	 * @return
	 */
	public static List<IPagePlugin> getPagePlugins() {
		return pagePlugins;
	}

	/**
	 * 获取所有插件
	 * @return
	 */
	public static List<ILinkPlugin> getLinkPlugins() {
		return linkPlugins;
	}

	public static void initLinkPlugin() {
		List<Class<?>> list = PluginUtil.getClasses("com.suyunyou.spider.plugins.link");
		for (Class<?> class1 : list) {
			try {
				ILinkPlugin plugin = (ILinkPlugin) class1.newInstance();
				PluginUtil.addILinkPlugin(plugin);
			} catch (Exception e) {
				LOGGER.error(e.getMessage(), e);
			}
		}
	}

	/** 
	 * 从包package中获取所有的Class 
	 * @param packageName 
	 * @return 
	 */
	public static List<Class<?>> getClasses(String packageName) {
		List<Class<?>> classes = classMap.get(packageName);
		if(classes != null) {
			return classes;
		}
		//第一个class类的集合
		classes = new ArrayList<Class<?>>();
		//是否循环迭代
		boolean recursive = true;
		//获取包的名字 并进行替换
		String packageDirName = packageName.replace('.', '/');
		//定义一个枚举的集合 并进行循环来处理这个目录下的things
		Enumeration<URL> dirs;
		try {
			dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
			//循环迭代下去
			while (dirs.hasMoreElements()){
				//获取下一个元素
				URL url = dirs.nextElement();
				//得到协议的名称
				String protocol = url.getProtocol();
				//如果是以文件的形式保存在服务器上
				if ("file".equals(protocol)) {
					//获取包的物理路径
					String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
					//以文件的方式扫描整个包下的文件 并添加到集合中
					findClassesInPackageByFile(packageName, filePath, recursive, classes);
				} else if ("jar".equals(protocol)){
					//如果是jar包文件 
					//定义一个JarFile
					JarFile jar;
					try {
						//获取jar
						jar = ((JarURLConnection) url.openConnection()).getJarFile();
						//从此jar包 得到一个枚举类
						Enumeration<JarEntry> entries = jar.entries();
						//同样的进行循环迭代
						while (entries.hasMoreElements()) {
							//获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
							JarEntry entry = entries.nextElement();
							String name = entry.getName();
							//如果是以/开头的
							if (name.charAt(0) == '/') {
								//获取后面的字符串
								name = name.substring(1);
							}
							//如果前半部分和定义的包名相同
							if (name.startsWith(packageDirName)) {
								int idx = name.lastIndexOf('/');
								//如果以"/"结尾 是一个包
								if (idx != -1) {
									//获取包名 把"/"替换成"."
									packageName = name.substring(0, idx).replace('/', '.');
								}
								//如果可以迭代下去 并且是一个包
								if ((idx != -1) || recursive){
									//如果是一个.class文件 而且不是目录
									if (name.endsWith(".class") && !entry.isDirectory()) {
										//去掉后面的".class" 获取真正的类名
										String className = name.substring(packageName.length() + 1, name.length() - 6);
										try {
											//添加到classes
											classes.add(Class.forName(packageName + '.' + className));
										} catch (ClassNotFoundException e) {
											LOGGER.error(e.getMessage(), e);
										}
									}
								}
							}
						}
					} catch (IOException e) {
						LOGGER.error(e.getMessage(), e);
					} 
				}
			}
		} catch (IOException e) {
			LOGGER.error(e.getMessage(), e);
		}
		classMap.put(packageName, classes);
		return classes;
	}

	/** 
	 * 以文件的形式来获取包下的所有Class 
	 * @param packageName 
	 * @param packagePath 
	 * @param recursive 
	 * @param classes 
	 */
	private static void findClassesInPackageByFile(String packageName, String packagePath, final boolean recursive, List<Class<?>> classes){
		//获取此包的目录 建立一个File
		File dir = new File(packagePath);
		//如果不存在或者 也不是目录就直接返回
		if (!dir.exists() || !dir.isDirectory()) {
			return;
		}
		//如果存在 就获取包下的所有文件 包括目录
		File[] dirfiles = dir.listFiles(new FileFilter() {
			//自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
			public boolean accept(File file) {
				return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));
			}
		});
		//循环所有文件
		for (File file : dirfiles) {
			//如果是目录 则继续扫描
			if (file.isDirectory()) {
				findClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
			} else {
				//如果是java类文件 去掉后面的.class 只留下类名
				String className = file.getName().substring(0, file.getName().length() - 6);
				try {
					//添加到集合中去
					classes.add(Class.forName(packageName + '.' + className));
				} catch (ClassNotFoundException e) {
					LOGGER.error(e.getMessage(), e);
				}
			}
		}
	} 

	public static void main(String[] args) throws Exception {
		List<Class<?>> list = getClasses("com.suyunyou.spider.plugins.page");
		for (Class<?> class1 : list) {
			System.out.println(class1.getName());
		}
		
		String content = "<a href=\"http://www.suyunyou.com/1/2.html\">csdf</a>";
		list = getClasses("com.suyunyou.spider.plugins.link");
		for (Class<?> class1 : list) {
			System.out.println(class1.getName());
			ILinkPlugin plugin = (ILinkPlugin) class1.newInstance();
			List<String> links = plugin.getLinks(content);
			System.out.println(FrameJsonUtil.toString(links));
		}

		/*//根据类名获取Class对象
		Class c = Class.forName("com.suyunyou.spider.plugins.PageDtlPlugin");
		//参数类型数组
		Class[] parameterTypes = {String.class};
		//根据参数类型获取相应的构造函数
		java.lang.reflect.Constructor constructor = c.getConstructor(parameterTypes);
		//参数数组
		Object[] parameters={"1"};
		//根据获取的构造函数和参数，创建实例
		Object o=constructor.newInstance(parameters);*/
	}
}